package be.kdg.bombermanunlimited.client.Game;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import be.kdg.bombermanunlimited.client.CentralRegistry;
import be.kdg.bombermanunlimited.client.CentralRegistry.BombermanObjects;
import be.kdg.bombermanunlimited.client.Interfaces.IGameToGui;
import be.kdg.bombermanunlimited.client.Interfaces.ILocalBomb;
import be.kdg.bombermanunlimited.client.Interfaces.ILocalPlayer;
import be.kdg.bombermanunlimited.client.gui.Board;
import be.kdg.bombermanunlimited.client.localPlayer.LocalBomb;
import be.kdg.bombermanunlimited.client.localPlayer.ProxyPlayer;
import be.kdg.bombermanunlimited.client.remote.interfaces.IGameListener;
import be.kdg.bombermanunlimited.server.objects.interfaces.IPlayer;
import be.kdg.bombermanunlimited.server.remote.interfaces.IGame;
import be.kdg.bombermanunlimited.server.remote.interfaces.ITile;

/**
 * 
 * clientGame: belangrijkste game klasse op de client die vooral voor interactie
 * met het RMI object IGame zal zorgen aanmaken van spel, opvragen van het
 * spelbord.
 * 
 * innerclass GameListener bevat functies die vanop de server worden
 * aangeroepen.
 * 
 * @author pieter
 * 
 */
public class ClientGame {

	IGame gameServer;
	private IGameToGui gui;
	private ILocalPlayer localPlayer;
	private List<ILocalPlayer> players;
	private List<ILocalBomb> bombs;
	private long updateInterval = 2000;

	public ClientGame(IGame gameServer) {
		players = new ArrayList<ILocalPlayer>();
		bombs = new ArrayList<ILocalBomb>();
		this.gameServer = gameServer;

		gui = new Board(gameServer);
		CentralRegistry reg = CentralRegistry.getRegistry();
		String username = reg.getString(BombermanObjects.USERNAME);
		setPlayer(username);
	}

	public Board getBoard() {
		return (Board) gui;
	}

	public void startGame() {
		gui.startGame();
	}

	/**
	 * maakt een speler lokaal aan en voegt zichzelf als speler toe op de
	 * server. hierbij wordt een instantie van de innerclass gameListener
	 * meegegeven. deze wordt gebruikt voor methode-oproepen vanop de server
	 * 
	 * @param username
	 */
	private void setPlayer(String username) {
		try {
			players = new ArrayList<ILocalPlayer>();
			IGameListener gameListener = new GameListener();
			IPlayer player = gameServer.addPlayer(username, gameListener);
			localPlayer = new ProxyPlayer(player, true);
			gui.addLocalPlayer(localPlayer);
		} catch (Exception e) {
			System.err.println("game setPlayerName exception:");
			e.printStackTrace();
		}
	}

	/**
	 * copy van een lijst met spelers vanop de server naar de lokale lijst met
	 * spelers
	 * 
	 * @param tempPlayers
	 * @throws RemoteException
	 */
	public synchronized void copyPlayers(List<IPlayer> tempPlayers)
			throws RemoteException {
		players = new ArrayList<ILocalPlayer>();
		for (int i = 0; i < tempPlayers.size(); i++) {

			players.add(new ProxyPlayer(tempPlayers.get(i), false));
			gui.addOtherPlayer(players.get(players.size() - 1));
		}
		for (int j = 0; j < players.size(); j++) {
			ILocalPlayer temp = players.get(j);
		}

	}

	/**
	 * innerclass GameListener, klasse die wordt gebruikt voor update oproepen
	 * vanop de server.
	 * 
	 * @author pieter
	 * 
	 */
	public class GameListener extends UnicastRemoteObject implements
			IGameListener {

		protected GameListener() throws RemoteException {
			super();
		}

		private static final long serialVersionUID = 1L;

		public synchronized void setLocalPlayer(IPlayer player)
				throws RemoteException {
			localPlayer = new ProxyPlayer(player, true);
		}

		public synchronized void setPlayers(List<IPlayer> p) {
			try {
				copyPlayers(p);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
		}

		/**
		 * lijsten met namen, rijen en kollommen worden doorgestuurd. deze
		 * waarden worden dan allemaal geupdate in de lokale lijst van spelers
		 */
		public synchronized void updatePlayers(String[] name, int[] row,
				int[] collumn) throws RemoteException {
			int i;
			for (i = 0; i < players.size(); i++) {
				players.get(i).update(name[i], row[i], collumn[i]);
			}
		}

		/**
		 * update van 1 speler
		 */
		public synchronized void updatePlayer(int index, IPlayer playerUpdate)
				throws RemoteException {
			players.get(index).update(playerUpdate.getName(),
					playerUpdate.getRow(), playerUpdate.getColumn());
		}

		/**
		 * wordt opgeroepen vanop de server wanneer er een speler aan het spel
		 * werd toegevoegd.
		 */
		public synchronized void addPlayer(IPlayer player)
				throws RemoteException {
			players.add(new ProxyPlayer(player, false));
			// System.out.println("[clientGame] addPlayer " +
			// players.get(players.size()-1).getName());
			gui.addOtherPlayer(players.get(players.size() - 1));
		}

		/**
		 * wanneer iemand een bom legt, gaan de server via deze oproep overal
		 * een bom toevoegn aan de lijst met bommen in de clients
		 */
		public synchronized void addBomb(int row, int column, int range) {
			bombs.add(new LocalBomb(row, column, range));
			gui.addBomb(row, column, range);
		}

		/**
		 * FIFO principe, oudste bom (op positie 0) wordt opgeblazen en verwijderd
		 */
		public synchronized void blowBomb() {
			bombs.remove(0);
			gui.blowBomb();
		}
		
		/**
		 * de hele map wordt hier in een vector doorgegeven van server naar client. gebeurd enkel in het begin van het spel
		 * 
		 */
		public void setMap(Vector<ITile> map) throws RemoteException {
			gui.setMap(map);
		}

		
		/**
		 * de tile op positie index wordt hier veranderd. dit kan enkel een opblaasbare tile zijn dat wordt weggeblazen
		 */
		public void changeTile(int index) throws RemoteException {
			gui.changeTile(index);
		}

		/**
		 * speler is gedood.
		 */
		public void gameOver() throws RemoteException {
			localPlayer.setDead();
			// System.out.println("player dood!");
			gui.gameOver();
		}

		/**
		 * een andere speler op index 'index' is gedood
		 */
		public void setDead(int index) throws RemoteException {
			players.get(index).setDead();
			gui.setDead(index);
		}

		@Override
		public void startGame() throws RemoteException {
			ClientGame.this.startGame();
		}

	}

}
